package com.example.springbootstartermqttprovider.yinhang;

import cn.hutool.json.JSONUtil;
import lombok.SneakyThrows;
import org.dom4j.DocumentException;
import org.dom4j.Element;

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class FileDownloadDemo {
    private static String signUrl = "http://61.181.98.22:4450";
    private static String verifyUrl = "http://61.181.98.22:4450";
    private static String signContentType = "INFOSEC_SIGN/1.0";
    private static String verifyContentType = "INFOSEC_VERIFY_SIGN/1.0";
    private static String sendType = "http";
    private static String host = "61.181.98.22";
    private static int port = 8008;


    private static int portNew = 8006;
	private static String downloadFilePath = "C:\\www";

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static final String CHARSET = "gb18030";

    public static void main(String[] args) throws IOException {
        WJ12Req wj12Req=new WJ12Req();
        wj12Req.setAcctNo("77250078801000001798");
        wj12Req.setFileDownloadPar("20250513100205993240");
        wj12Req.setFileDownloadFlag(1);
//        wj12Req.setFileDownloadPar("1");
        //请求参数
        System.out.println("请求参数  =========="+JSONUtil.toJsonStr(wj12Req));
        String body =new FileDownloadDemo().BodyBeanToXml(wj12Req,"gb18030");
        String head = new FileDownloadDemo().getHeadXmlByTranceId("WJ12", "2027726208");
        String sendJson =new FileDownloadDemo().getSendJson(head,body);
        //step2: �õ����ĺ�ƴ�ӱ��ģ����ͽ���
//        String send = "XXXXXX<?xml version=\"1.0\" encoding=\"gb2312\"?><packet><head>.......</head><body><signature>"+sign+"</signature></body></packet>";//ƴ�ӱ���
//        String result = sendFileByDownload(sendJson);
//        System.out.println("returnMsg  rcv from host is : " + new String(result));

    }
    @SneakyThrows
    public String getSendJson(String head, String body) {
        InputStream in = getSendSignBody(body.getBytes(CHARSET), signContentType, signUrl);
        String sign = parseSignContent(in);
        String format = String.format("<?xml version=\"1.0\" encoding=\"gb18030\"?><packet>%s<body><signature>%s</signature></body></packet>", head, sign);
        int length = format.length() + 6;
        String formattedLength = String.format("%06d", length);
        format = formattedLength + format;
        return format;
    }


    @SneakyThrows
    public String sendByHttp(String xmlString) {

        System.out.println("the protocol is :" + sendType);
        System.out.println("the data send to host is :" + xmlString);

        InputStream in = null;
        byte[] rcv = null;
        byte[] sendByte = xmlString.getBytes();
        String urlStr = "http://" + host + ":" + portNew + "/";
        System.out.println("the url is :" + urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection;
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.getOutputStream().write(sendByte);
            connection.getOutputStream().flush();
            in = connection.getInputStream();
            //读取返回的前6个字节，获得报文总长度
            byte[] lengthdata = new byte[6];
            int i = in.read(lengthdata);
            String lengthstr = (new String(lengthdata)).trim();
            int length = Integer.parseInt(lengthstr);
            //根据报文总长度读取后续报文
            rcv = new byte[length];
            int j = 0;
            byte[] rcvtmp = new byte[10240];
            int srcindex = 0;
            while (j >= 0) {
                j = in.read(rcvtmp);
                if (j < 0) {
                    break;
                }
                System.arraycopy(rcvtmp, 0, rcv, srcindex, j);
                srcindex = srcindex + j;
            }
            in.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(rcv);
    }
    @SneakyThrows
    public Map getReturnBody(boolean flag, String retSign) {
        if (flag) {
            retSign = retSign.substring(retSign.indexOf("<signature>") + 11, retSign.indexOf("</signature>"));
        }
        InputStream in = getSendSignBody(retSign.getBytes(), verifyContentType, verifyUrl);
        Map verify = parseVerifyContent(in);
        in.close();
        return verify;
    }

    public <T> T XmlToBean(String xml, Class<T> clazz) {
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();

            // 使用StringReader来读取XML字符串
            StringReader reader = new StringReader(xml);

            // 将XML字符串转换为Java对象
            @SuppressWarnings("unchecked")
            T obj = (T) unmarshaller.unmarshal(reader);

            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @paramcontent, contentType, url]
     * @return java.io.InputStream
     * @describe 签名验签公共发送报文类
     * @date 2019/12/6
     */
    public InputStream getSendSignBody(byte[] content, String contentType, String url) throws IOException {
        URL urll = new URL(url);
        HttpURLConnection con1 = (HttpURLConnection) urll.openConnection();//配置报文头
        con1.setDoInput(true);
        con1.setDoOutput(true);
        con1.setRequestMethod("POST");
        con1.setRequestProperty("Content-Type", contentType);
        con1.setRequestProperty("Content-Length", String.valueOf(content.length));
        con1.connect();
        con1.getOutputStream().write(content);
        con1.getOutputStream().flush();
        InputStream in = con1.getInputStream();
        return in;
    }
    public String BodyBeanToXml(Object o, String code) {
        try {
            JAXBContext context = JAXBContext.newInstance(o.getClass());
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING, code);
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            StringWriter sw = new StringWriter();
            marshaller.marshal(o, sw);
            String xmlObj = sw.toString();
            return sw.toString().replace("standalone=\"yes\"", "");
        } catch (JAXBException e) {
            e.printStackTrace();
//            throw new ServiceException("转化为XML字符串异常");
        }
        return "";
    }

    public String getHeadXmlByTranceId(String transCode, String masterID) {
        Head head = new Head();
        head.setTransCode(transCode);
        head.setSignFlag("1");
        head.setPacketID(System.currentTimeMillis() + "");
        head.setMasterID(masterID);
        head.setTimeStamp(sdf.format(new Date()));
        String headString = BodyBeanToXml(head, CHARSET);
        return headString;
    }

    /**
     * @return java.lang.String
     * @describe 文件下载Demo
     */
    public static String sendFileByDownload(String send,String ty) {
        System.out.println("the data send to host is :" + send);

        String urlstr = "http://" + host + ":" + port + "/" + "fileTransfer/";//请求url，fileTransfer/不能少
        System.out.println("the url is :" + urlstr);
        InputStream in = null;
        byte[] rcv = null;
        String contentstr="";
        try {

            URL url = new URL(urlstr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.getOutputStream().write(send.getBytes());
            connection.getOutputStream().flush();

            //先读取前6个字节，获取报文（不含文件流）长度
            byte lengthdata[] = new byte[6];
            in = connection.getInputStream();
            in.read(lengthdata);
            String lengthstr = (new String(lengthdata)).trim();
            int length = Integer.parseInt(lengthstr);
            rcv = new byte[length];
            int j = 0;

            int srcindex = 0;
            //读取报文内容（不含文件流）
            while(j>=0){
                byte[] rcvtmp = new byte[length-6-j];
                j=in.read(rcvtmp);
                if(j<0){
                    break;
                }
                System.arraycopy(rcvtmp ,0 , rcv , srcindex , j);
                srcindex = srcindex + j;
                if(srcindex==length-6){
                    break;
                }
            }
            contentstr = new String(rcv,CHARSET);
            //将返回报文中的signature密文进行验签，获取交易返回的body明文
            String retSign = contentstr.substring(contentstr.indexOf("<signature>")+11,contentstr.indexOf("</signature>"));

//            return retSign;
//            InputStream in2 = send(retSign.getBytes(), verifyContentType, verifyUrl);
//            Map verify = parseVerifyContent(in2);
//            in2.close();

            //获取返回报文中的文件长度和文件名
//            String retfileLengthStr = (String) verify.get("fileLength");
//            String retfileName = (String) verify.get("fileName");

            String retfileLengthStr = retSign.length()+"";
            String retfileName = ty;
            if (!StringUtils.isEmpty(retfileLengthStr) || !StringUtils.isEmpty(retfileName)) {
                int fileLeng = Integer.valueOf(retfileLengthStr);
                String systemTempDir = System.getProperty("java.io.tmpdir");
                File tempFile = new File(systemTempDir + "/" + retfileName);
                if (tempFile.exists()) {
                    tempFile.delete();
                }
                FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
                byte[] readTemp = new byte[8096];
                int k = 0;
                int byteCounts = 0;

                while (k >= 0 || byteCounts < fileLeng) {
                    //设置缓字节冲数组，继续读流，读到文件输出流之中
                    k = in.read(readTemp);
                    if (k < 0) {
                        break;
                    }
                    fileOutputStream.write(readTemp, 0, k);
                    byteCounts += k;
                }
                fileOutputStream.close();
                System.out.println("共计接收文件字节数为：" + byteCounts);
            }
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return contentstr;
    }

    /**
     * @param
     * @return java.io.InputStream
     * @describe 签名验签公共发送报文类
     * @date 2019/12/6
     */
    public static InputStream send(byte[] content, String contentType, String url) throws IOException {
        URL urll = new URL(url);
        HttpURLConnection con1 = (HttpURLConnection) urll.openConnection();//配置报文头
        con1.setDoInput(true);
        con1.setDoOutput(true);
        con1.setRequestMethod("POST");
        con1.setRequestProperty("Content-Type", contentType);
        con1.setRequestProperty("Content-Length", String.valueOf(content.length));
        con1.connect();
        con1.getOutputStream().write(content);
        con1.getOutputStream().flush();
        System.out.println(con1.getResponseCode());
        System.out.println(con1.getResponseMessage());
        InputStream in = con1.getInputStream();
        return in;
    }


    public static String parseSignContent(InputStream in) {
        try {
            Element el = parse(in);
            String result = el.element("head").element("result").getTextTrim();
            if (result.equals("0")){
                return el.element("body").element("sign").getText();
            } else{
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Map parseVerifyContent(InputStream in) {
        Map context = new HashMap();
        try {
            Element el = parse(in);
            String result = el.element("head").element("result").getTextTrim();
            if (result.equals("0")) {
                String content =
                        el.element("body").element("sic").element("body").asXML();
                String DN = el.element("body").element("certdn").getText();
                context.put("plain", content);
                context.put("dn", DN);
                return context;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static Element parse(InputStream io) throws DocumentException,UnsupportedEncodingException {
        SAXReader reader = new SAXReader();
        reader.setValidation(false);
        InputStreamReader bi = new InputStreamReader(io, CHARSET);
        Document doc = null;
        doc = reader.read(bi);
        return doc.getRootElement();
    }
}
